#[cfg(feature = "ssr")]
use crate::base::{mysql::get_columns, Error, Result};
#[cfg(feature = "ssr")]
use crate::cache::table_cache::get_id_by_label;
#[cfg(feature = "ssr")]
use crate::cache::table_cache::{
    get_ids_by_label, get_label_by_id, is_fiter_ok, search_values, GeneralTableCache,
    TableCacheTrait,
};
#[cfg(feature = "ssr")]
use crate::prelude::FieldProps;
use crate::{
    prelude::{Direction, FieldType, WhereCause},
    utils::json_value_to_string,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;

use super::{has_duplicates, KvItem, TreeNode};
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Options {
    Array(Vec<String>),
    Map(Vec<KvItem>),
    Tree(Vec<TreeNode>),
    Fetch(FetchParams),
}
#[cfg(feature = "ssr")]
impl Options {
    pub async fn parse(&mut self, fetch_table_cols:&[FieldProps]) -> Result<()> {
        self.convert_fetch().await?;
        match self {
            Options::Array(vals) => {
                if vals.is_empty() {
                    return Err(Error::Conf("options参数中Array不能为空".to_string()));
                }
                if has_duplicates(&vals) {
                    return Err(Error::Conf("options参数中Array不能有重复值".to_string()));
                }
            }
            Options::Map(vals) => {
                if vals.is_empty() {
                    return Err(Error::Conf("options参数中Map不能为空".to_string()));
                }
                let keys: Vec<&str> = vals.iter().map(|v| v.value.as_str()).collect();
                if has_duplicates(&keys) {
                    return Err(Error::Conf(
                        "options参数中Map的value不能有重复值".to_string(),
                    ));
                }
            }
            Options::Tree(vals) => {
                if vals.is_empty() {
                    return Err(Error::Conf("options参数中Tree不能为空".to_string()));
                }
                let keys: Vec<&str> = vals.iter().map(|v| v.key.as_str()).collect();
                if has_duplicates(&keys) {
                    return Err(Error::Conf(
                        "options参数中Tree的key不能有重复值".to_string(),
                    ));
                }
            }
            Options::Fetch(fp) => {
                if fp.table_name.is_empty() {
                    return Err(Error::Conf("fetch参数中dao_name不能为空".to_string()));
                }
                if fp.label_col.is_empty() {
                    return Err(Error::Conf("fetch参数中label_col不能为空".to_string()));
                }
                if fp.value_col.is_empty() {
                    return Err(Error::Conf("fetch参数中value_col不能为空".to_string()));
                }
                if fp.parent_col.is_some() && fp.parent_col.as_ref().unwrap().is_empty() {
                    return Err(Error::Conf("fetch参数中parent_col不能为空".to_string()));
                }
                if fp.search_cols.is_some() && fp.search_cols.as_ref().unwrap().is_empty() {
                    return Err(Error::Conf("fetch参数中search_cols不能为空".to_string()));
                }
                if let Some(wcs) = fp.where_cause.as_ref() {
                    if wcs.is_empty() {
                        return Err(Error::Conf("fetch参数中where_cause不能为空".to_string()));
                    }
                }
                if fp.search_cols.is_some() {
                    let tc = GeneralTableCache::new(fp.table_name.as_str());
                    let vcol=fp.value_col.as_str();
                    let vtype=fetch_table_cols.iter()
                        .find(|f| f.name == vcol)
                        .map(|f| &f.field_type)
                        .ok_or_else(|| Error::Conf(format!("value_col:{}在表{}中不存在", vcol, fp.table_name)))?;
                    let lcol=fp.label_col.as_str();
                    let ltype=fetch_table_cols.iter()
                        .find(|f| f.name == lcol)
                        .map(|f| &f.field_type)
                        .ok_or_else(|| Error::Conf(format!("label_col:{}在表{}中不存在", lcol, fp.table_name)))?;
                    let mut fds: Vec<(&str, &FieldType)> = vec![
                        (vcol, vtype),
                        (lcol, ltype),
                    ];
                    if let Some(pcol) = fp.parent_col.as_deref() {
                        fds.push((pcol, vtype));
                    }
                    if let Some(scols) = fp.search_cols.as_deref() {
                        for col in scols.iter() {
                            let stype= fetch_table_cols.iter()
                                .find(|f| f.name == *col)
                                .map(|f| &f.field_type)
                                .ok_or_else(|| Error::Conf(format!("search_cols:{}在表{}中不存在", col, fp.table_name)))?;
                            fds.push((col.as_str(), stype));
                        }
                    }
                    tc.load_all(
                        (&fp.value_col, vtype),
                        fds,
                        fp.where_cause.as_deref(),
                        fp.order_by.as_deref(),
                    )
                    .await?;
                }
            }
        }
        Ok(())
    }
    pub(crate) async fn get_key_by_label(&self, label: &str) -> anyhow::Result<Option<String>> {
        match self {
            Options::Array(vals) => {
                if vals.contains(&label.to_string()) {
                    return Ok(Some(label.to_string()));
                }
            }
            Options::Map(vals) => {
                for val in vals.iter() {
                    if val.label == label {
                        return Ok(Some(val.value.clone()));
                    }
                }
            }
            Options::Tree(vals) => {
                for val in vals.iter() {
                    if val.title == label {
                        return Ok(Some(val.key.clone()));
                    }
                }
            }
            Options::Fetch(fp) => {
                if fp.search_cols.is_some() {
                    let tc = GeneralTableCache::new(fp.table_name.as_str());
                    let v = tc.get_id_by_label(fp.label_col.as_str(), label)?;
                    return Ok(v);
                } else {
                    let v = get_id_by_label(
                        &fp.table_name,
                        (fp.label_col.as_str(), label),
                        fp.value_col.as_str(),
                    )
                    .await?;
                    return Ok(v);
                }
            }
        }
        Ok(None)
    }
    pub(crate) async fn get_label_by_key(&self, key: &str) -> anyhow::Result<Option<String>> {
        match self {
            Options::Array(_) => {
                return Ok(Some(key.to_string()));
            }
            Options::Map(vals) => {
                for val in vals.iter() {
                    if val.value == key {
                        return Ok(Some(val.label.clone()));
                    }
                }
            }
            Options::Tree(vals) => {
                for val in vals.iter() {
                    if val.key == key {
                        return Ok(Some(val.title.clone()));
                    }
                }
            }
            Options::Fetch(fp) => {
                if fp.search_cols.is_some() {
                    let tc = GeneralTableCache::new(fp.table_name.as_str());
                    let v = tc.get_field_by_id(key, fp.label_col.as_str())?;
                    return Ok(v);
                } else {
                    let v = get_label_by_id(
                        &fp.table_name,
                        (fp.value_col.as_str(), key),
                        fp.label_col.as_str(),
                    )
                    .await
                    .or_else(|err| {
                        if err.to_string().contains("没有找到") {
                            Ok(None)
                        } else {
                            Err(err)
                        }
                    })?;
                    return Ok(v);
                }
            }
        }
        Ok(None)
    }
    pub(crate) async fn get_keys_by_label<'a>(
        &self,
        filter: Option<&WhereCause>,
        order: Option<Direction>,
    ) -> anyhow::Result<Vec<String>> {
        let mut keys: Vec<String> = Vec::new();
        match self {
            Options::Array(vals) => {
                for val in vals.iter() {
                    if is_fiter_ok(val, filter)? {
                        keys.push(val.to_string());
                    }
                }
            }
            Options::Map(vals) => {
                for val in vals.iter() {
                    if is_fiter_ok(&val.label, filter)? {
                        keys.push(val.value.clone());
                    }
                }
            }
            Options::Tree(vals) => {
                for val in vals.iter() {
                    if is_fiter_ok(&val.title, filter)? {
                        keys.push(val.key.clone());
                    }
                }
            }
            Options::Fetch(fp) => {
                let vals = if fp.search_cols.is_some() {
                    let tc = GeneralTableCache::new(fp.table_name.as_str());
                    tc.get_ids_by_field(fp.label_col.as_str(), filter, order)?
                } else {
                    get_ids_by_label(
                        &fp.table_name,
                        &fp.value_col,
                        fp.label_col.as_str(),
                        filter,
                        fp.where_cause.as_deref(),
                        fp.order_by.as_deref(),
                    )
                    .await?
                };
                for val in vals.into_iter() {
                    keys.push(val);
                }
            }
        }
        Ok(keys)
    }
    pub async fn search_values<'a>(&self, value: &str) -> anyhow::Result<Vec<(String, String)>> {
        if let Options::Fetch(fp) = self {
            let scols = fp
                .search_cols
                .as_ref()
                .ok_or(anyhow::anyhow!("没有配置搜索字段"))?
                .iter()
                .map(|v| v.as_str())
                .collect::<Vec<&str>>();
            if fp.search_cols.is_some() {
                let tc = GeneralTableCache::new(fp.table_name.as_str());
                let vals = tc
                    .search_values(value, &fp.label_col, scols.as_slice())
                    .map_err(|err| {
                        anyhow::anyhow!("查询数据失败，表名：{}，错误信息：{}", fp.table_name, err)
                    })?;
                return Ok(vals);
            } else {
                let vals = search_values(
                    value,
                    &fp.table_name,
                    &fp.value_col,
                    fp.label_col.as_str(),
                    scols.as_slice(),
                )
                .await?;
                return Ok(vals);
            }
        }
        anyhow::bail!("当前Options不是Fetch类型");
    }
    pub async fn convert_fetch(&mut self) -> anyhow::Result<()> {
        use crate::prelude::find_list_data;
        if let Options::Fetch(fp) = self {
            if fp.search_cols.is_some() {
                return Ok(());
            }
            let table_name = fp.table_name.as_str();
            let wcs = fp.where_cause.as_deref();
            let ords = fp.order_by.as_deref();
            let mut sel_cos = vec![fp.label_col.as_str(), fp.value_col.as_str()];
            if let Some(pcol) = fp.parent_col.as_deref() {
                sel_cos.push(pcol);
            }
            let values = find_list_data(table_name, &sel_cos, wcs, ords)
                .await
                .map_err(|err| {
                    anyhow::anyhow!("查询数据失败，表名：{}，错误信息：{}", table_name, err)
                })?;
            let mut nodes: Vec<TreeNode> = Vec::new();
            for val in values.iter() {
                if let Value::Object(ov) = val {
                    let key = ov
                        .get(fp.value_col.as_str())
                        .map(|v| json_value_to_string(v))
                        .ok_or(anyhow::anyhow!("没有找到{}字段", fp.value_col))?;
                    let title = ov
                        .get(fp.label_col.as_str())
                        .map(|v| json_value_to_string(v))
                        .ok_or(anyhow::anyhow!("没有找到{}字段", fp.label_col))?;
                    let mut pkey: Option<String> = None;
                    if let Some(pcol) = fp.parent_col.as_deref() {
                        pkey = ov.get(pcol).map(|v| json_value_to_string(v));
                    }
                    nodes.push(TreeNode {
                        key,
                        title,
                        parent_key: pkey,
                    });
                }
            }
            if fp.parent_col.is_none() {
                let mut items: Vec<KvItem> = Vec::new();
                for node in nodes.into_iter() {
                    items.push({
                        KvItem {
                            label: node.title,
                            value: node.key,
                        }
                    });
                }
                *self = Options::Map(items);
            } else {
                *self = Options::Tree(nodes);
            }
        }
        Ok(())
    }
}

/** Fetch参数 */
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct FetchParams {
    /** table_name */
    pub table_name: String,
    /** 标题的字段名 */
    pub label_col: String,
    /** 值的字段名 */
    pub value_col: String,
    /** 父级值的字段名 */
    pub parent_col: Option<String>,
    /** 查询条件 */
    pub where_cause: Option<String>,
    /** 排序 */
    pub order_by: Option<String>,
    /** 搜索的字段名，当控件类型为Search时需要 */
    pub search_cols: Option<Vec<String>>,
}
#[cfg(feature = "ssr")]
impl FetchParams {
    pub async fn parse(&self) -> Result<()> {
        if self.table_name.is_empty() {
            return Err(Error::Conf("table_name不能为空".to_string()));
        }
        if self.label_col.is_empty() {
            return Err(Error::Conf("label_col不能为空".to_string()));
        }
        let fps = get_columns(self.table_name.as_str()).await.map_err(|err| {
            anyhow::anyhow!(
                "获取表格字段失败，表名：{}，错误信息：{}",
                self.table_name,
                err
            )
        })?;
        if fps.is_empty() {
            return Err(Error::Conf(format!(
                "table_name:{}在数据库中不存在",
                self.table_name
            )));
        }
        let is_ok = fps.iter().any(|fp| fp.name == self.label_col);
        if !is_ok {
            return Err(Error::Conf(format!(
                "label_col:{}在实体类{}不存在",
                self.label_col,
                self.table_name.as_str()
            )));
        }
        if self.value_col.is_empty() {
            return Err(Error::Conf("value_col不能为空".to_string()));
        }
        let is_ok = fps.iter().any(|fp| fp.name == self.value_col);
        if !is_ok {
            return Err(Error::Conf(format!(
                "value_col:{}在实体类{}不存在",
                self.value_col,
                self.table_name.as_str()
            )));
        }
        if let Some(scols) = self.search_cols.as_ref() {
            for col in scols.iter() {
                let is_ok = fps.iter().any(|fp| fp.name == *col);
                if !is_ok {
                    return Err(Error::Conf(format!(
                        "search_cols:{}在实体类{}不存在",
                        col,
                        self.table_name.as_str()
                    )));
                }
            }
        }
        if let Some(ss) = &self.order_by {
            if ss.is_empty() {
                return Err(Error::Conf("order_by不能为空".to_string()));
            }
        }
        if let Some(wc) = &self.where_cause {
            if wc.is_empty() {
                return Err(Error::Conf("where_cause不能为空".to_string()));
            }
        }
        Ok(())
    }
}
